package compFile;


import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.zip.ZipInputStream;

import org.apache.commons.codec.digest.DigestUtils;
import org.eclipse.jgit.diff.DiffAlgorithm;
import org.eclipse.jgit.diff.DiffAlgorithm.SupportedAlgorithm;
import org.eclipse.jgit.diff.DiffFormatter;
import org.eclipse.jgit.diff.EditList;
import org.eclipse.jgit.diff.RawText;
import org.eclipse.jgit.diff.RawTextComparator;

import dbConn.fileInfo;

//源代码比较（java）, 将比较的差异信息，记录到数据库中

public class compareFile {
	private final static char[] hexArray = "0123456789ABCDEF".toCharArray();

	//private static String strBaseVersionDir = "D:/XMOS/sourceCode/giveda-GOSP-V1.0.1";
	//private static String strCompareVersionDir = "D:/XMOS/sourceCode/giveda-GOSP-V2.0.2";
	public static List<fileInfo> listFileInfos = new ArrayList<fileInfo>();
	public static List<List<Object>> listJson = new ArrayList<List<Object>>();
	
//	public static void main(String[] args) {
//		// TODO Auto-generated method stub
//		System.out.println("main start");
//		Long startTime = System.currentTimeMillis();
//		DBconn.init();
//		testCode();
//		String sqlString = "insert into version_compare VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
//		System.out.println("listJson = " + listJson.size());
//		Long startTime2 = System.currentTimeMillis();
//		DBconn.insertSql(sqlString, listJson, 100);
//		//DBconn.closeConn(DBconn.rc, null, null);
//		DBconn.closeConn();
//		Long endTime = System.currentTimeMillis();
//		System.out.println("main end, times = " + (endTime - startTime2));
//		System.out.println("main end, times = " + (endTime - startTime));
//	}
 
	public static String getDiffWithFile(File file1, File file2) throws IOException {
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		long nlen1 = file1.length();
		long nlen2 = file2.length();
		if (nlen1 > 5000000 || nlen2 > 5000000) {
			return "";
		}
		RawText aRawText = new RawText(file1);
		RawText bRawText = new RawText(file2);

		EditList rEditList = DiffAlgorithm.getAlgorithm(SupportedAlgorithm.MYERS).diff(RawTextComparator.DEFAULT,
				aRawText, bRawText);

		DiffFormatter formatter = new DiffFormatter(out);
		formatter.format(rEditList, aRawText, bRawText);
		String outString = new String(out.toByteArray());
		out.close();
		formatter.close();
		return outString;
	}

	// hashType的值："MD5"，"SHA1"，"SHA-256"，"SHA-384"，"SHA-512"
	@SuppressWarnings("unused")
	private static String getHash(String fileName, String hashType) throws Exception {
		InputStream fis;

		fis = new FileInputStream(fileName);
		byte buffer[] = new byte[1024];
		MessageDigest md5 = MessageDigest.getInstance("SHA-384");
		for (int numRead = 0; (numRead = fis.read(buffer)) > 0;) {
			md5.update(buffer, 0, numRead);
		}
		fis.close();
		return toHexString(md5.digest());

	}

	public static String toHexString(byte... bytes) {
		char[] hexChars = new char[bytes.length * 2];
		for (int j = 0; j < bytes.length; j++) {
			int v = bytes[j] & 0xFF;
			hexChars[j * 2] = hexArray[v >>> 4];
			hexChars[j * 2 + 1] = hexArray[v & 0x0F];
		}
		return new String(hexChars);
	}

	@SuppressWarnings("unused")
	public static void testCode(String baseDir, String cmpDir, String resDir) {
		//Main myCaseMain = new Main();
				
		try {
			FileWriter fileWritter = new FileWriter(resDir, true);
			String strBaseDir = baseDir;
			String strNewDir = cmpDir;

			BufferedWriter bw = new BufferedWriter(fileWritter);
			List<Object> othList = new ArrayList<Object>();
			List<String> listNames = new ArrayList<String>();
			readDirOrFile(listNames, bw, strBaseDir, strNewDir, othList);
			
			// 比较新目录下是否新增了文件，有新增则增加记录到数据库中
			List<String> listDir = new ArrayList<String>();
			List<String> listName = new ArrayList<String>();
			getDirAllFile(listDir, listName, strNewDir);
			for (String tmp : listName) {
				if (!othList.contains(tmp)) {
					//System.out.println(tmp);
								
					// 记录到数据库中
					File temFile = new File(tmp);
					String sqlString = "insert into version_compare VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
					List<Object> list = new ArrayList<Object>();
					list.add(null);
					list.add(temFile.getName());
					list.add(tmp);
					list.add("V1.0.1");
					list.add("V2.0.2");
					list.add(0);
					list.add(temFile.length());
					list.add("");
					list.add("");
					
					Calendar cal = Calendar.getInstance();
					long time = temFile.lastModified();
					SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
					cal.setTimeInMillis(time);
					String strModifyTime = formatter.format(cal.getTime());
					
					String strRemark = "The file is not available in the base version";
					list.add(strModifyTime);
					list.add(strRemark);
					
					// 把所有的数据保存到list中
					listJson.add(list);
					
					//DBconn.insertSql(sqlString, list);
					
					// 数据保存起来，后面插入数据库，提示效率
					fileInfo info = new fileInfo();
					info.setFile_name(temFile.getName());
					info.setFile_path(tmp);
					info.setBase_version("V1.0.1");
					info.setCompasre_version("V2.0.2");
					info.setBase_size(0);
					info.setCompaer_size(temFile.length());
					info.setDifference("");
					info.setIntroduction("");
					info.setModify_time(strModifyTime);
					info.setRemark(strRemark);
					listFileInfos.add(info);
				}
			}
			
			bw.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/*
	 * (non-Java-doc)
	 * 
	 * @see java.lang.Object#Object()
	 */
//	public void Main() {
//		super();
//	}

	public static void getDirAllFile(List<String> listDir, List<String> listName, String strDir) {
		listDir.add(strDir);
		while (!listDir.isEmpty()) {
			File[] files = new File(listDir.get(0)).listFiles();
			listDir.remove(0);
			if (files == null || files.length == 0) {
				//System.out.println(file.getAbsolutePath());
				continue;
			}
			
			for (File tmpFile : files) {
				if (tmpFile.isDirectory()) {
					listDir.add(tmpFile.getAbsolutePath());
				} else {
					String strTmpName = tmpFile.getAbsolutePath().substring(strDir.length());
					listName.add(strTmpName);
				}
			}
		}
	}
	
	public void compareTwoFile(String strFile1, String strFile2) {
		File file1 = new File(strFile1);
		File file2 = new File(strFile2);
		try {
			List<String> list1 = Files.readAllLines(file1.toPath());
			List<String> list2 = Files.readAllLines(file2.toPath());

			int nMin = list1.size() > list2.size() ? list2.size() : list1.size();
			// 逐行比较两个版本的源文件
			for (int i = 0; i < nMin; i++) {
				if (!list1.get(i).equals(list2.get(i))) {
					System.out.println((i + 1) + " hang not equal");
				}
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public String reName(String nameString) {
		String outNameString = nameString;
		if (nameString.endsWith(".iso")) {
			File myOldFile = new File(nameString);
			outNameString = nameString.replaceAll(".iso", ".zip");
			File myNewFile = new File(outNameString);
			myOldFile.renameTo(myNewFile);
		}
		return outNameString;
	}

	// 比较并获取两个同名文件的不同
	@SuppressWarnings("unused")
	public static void diffTwoFile(File fileName, BufferedWriter bw, String baseDirName, String cmpDirName, List<Object> othList) {
		String strAllNameString = fileName.getAbsolutePath();
		// int nHashCode = tmp.hashCode();
		long nlen = fileName.length();
		String strMd5;
		try {
			strMd5 = DigestUtils.md5Hex(new FileInputStream(fileName));

			Calendar cal = Calendar.getInstance();
			long time = fileName.lastModified();
			SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
			cal.setTimeInMillis(time);
			String strModifyTime = formatter.format(cal.getTime());

			bw.write(strAllNameString + "\t" + strMd5 + "\t" + strModifyTime + "\t" + nlen);
			bw.newLine();

			String strTmpName = strAllNameString.substring(baseDirName.length());
			// baseMap.put(strTmpName, strMd5);

			String strDir = cmpDirName;
			String strNewFile = strDir + strTmpName;
			File newFile = new File(strNewFile);
			long nLenNew = 0;
			String strDiffInfoString = "";
			String strRemark = "";
			if (newFile.exists() && newFile.length() < 300000) {
				strDiffInfoString = getDiffWithFile(fileName, newFile);
				//System.out.println(strTmpName + " strDiffInfoString = " + strDiffInfoString.length());
				if (strDiffInfoString.equals("")) {
					strRemark = "Both versions have the same content";
				}
				bw.write(strDiffInfoString);
				bw.newLine();
				nLenNew = newFile.length();
				othList.add(strTmpName);
			} else {
				System.out.println(strNewFile + " is not exists");
				strRemark = "the file compare_version hava not exists";
			}

			// strTmpName = strTmpName.replace("\\", "\\\\"); // 路径等反斜杠需要转义
			String sqlString = "insert into version_compare VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
			List<Object> list = new ArrayList<Object>();
			list.add(null);
			list.add(fileName.getName());
			list.add(strTmpName);
			list.add("V1.0.1");
			list.add("V2.0.2");
			list.add(nlen);
			list.add(nLenNew);
			list.add(strDiffInfoString);
			list.add("");
			list.add(strModifyTime);
			list.add(strRemark);
			
			// 把所有的数据保存到list中
			listJson.add(list);
			
			//DBconn.insertSql(sqlString, list);
			bw.newLine();
			
			// 数据保存起来，后面插入数据库，提示效率
			fileInfo info = new fileInfo();
			info.setFile_name(fileName.getName());
			info.setFile_path(strTmpName);
			info.setBase_version("V1.0.1");
			info.setCompasre_version("V2.0.2");
			info.setBase_size(nlen);
			info.setCompaer_size(nLenNew);
			info.setDifference(strDiffInfoString);
			info.setIntroduction("");
			info.setModify_time(strModifyTime);
			info.setRemark(strRemark);
			listFileInfos.add(info);
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	// 循环读取文件，并输出文件的详细信息，包括如下
	// 1、文件全名称，2、文件哈希值，3、文件大小等等
	public static void readDirOrFile(List<String> listNames, BufferedWriter bw, String baseDirName, String cmpDirName, List<Object> othList) {
		listNames.add(baseDirName);
		while(!listNames.isEmpty()) {
			File[] files = new File(listNames.get(0)).listFiles();
			listNames.remove(0);
			if (files == null || files.length == 0) {
				continue;
			}
			for (File tmp : files) {
				if (tmp.isDirectory()) {
					listNames.add(tmp.getAbsolutePath());
				} else {
					diffTwoFile(tmp, bw, baseDirName, cmpDirName, othList);
				}
			}
		}
	}

	// 读取文件，并输出文件相关信息
	public void ReadIsoFile(String filePathName) {
		String strPathName = reName(filePathName);
		System.out.println(strPathName);
		File myFile = new File(strPathName);
		if (!myFile.exists()) {
			System.out.println(filePathName + " is not exists");
			return;
		}

		String parentString = myFile.getParent() + "/";
		Charset myCharset = Charset.forName("utf-8");
		try 
		{
			System.out.println(myFile.getAbsolutePath());
			ZipInputStream zis = new ZipInputStream(new FileInputStream(myFile), myCharset);
			
			java.util.zip.ZipEntry entry = null;
			BufferedOutputStream bos = null;
			while ((entry = zis.getNextEntry()) != null) 
			{
				System.out.println(parentString + entry.getName());
				File filePath = new File(parentString + entry.getName());
				if (entry.isDirectory()) 
				{
					if (!filePath.exists()) 
					{
						filePath.mkdirs();
					}
				} 
				else 
				{
					FileOutputStream fos = new FileOutputStream(parentString + entry.getName());
					bos = new BufferedOutputStream(fos);
					byte[] buf = new byte[10 * 1024 * 1024];
					int len = 0;
					while ((len = zis.read(buf)) != -1) {
						bos.write(buf, 0, len);
					}
					bos.close();
				}
			}
			zis.closeEntry();
			zis.close();

		} 
		catch (IOException e) 
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

}
